﻿using System;
using System.Collections.Generic;
using System.IO;

namespace CodeRun.Util
{
    public interface ILogger
    {
        void Error(string msg, params object[] args);
        void Inform(string msg, params object[] args);
        void Warn(string msg, params object[] args);
        void Write(string format, params object[] args);
        void WriteLine(string format, params object[] args);
        void WriteLine();
    }

    public class Logger
    {
        public static ILogger Console;
        public static ILogger Null;

        static Logger()
        {
            Null = new NullLogger();
            Console = new ConsoleLogger();
        }
    }

    internal class NullLogger : ILogger
    {
        #region ILogger Members

        public void Error(string msg, params object[] args)
        {
        }

        public void Inform(string msg, params object[] args)
        {
        }

        public void Warn(string msg, params object[] args)
        {
        }

        public void Write(string format, params object[] args)
        {
        }

        public void WriteLine(string format, params object[] args)
        {
        }


        public void WriteLine()
        {
        }

        #endregion
    }

    public class TextWriterLogger : ILogger
    {
        private readonly TextWriter Output;

        public TextWriterLogger(TextWriter output)
        {
            Output = output;
        }

        #region ILogger Members

        public void Inform(string msg, params object[] args)
        {
            Output.Write("message: ");
            Output.WriteLine(msg, args);
        }

        public void Warn(string msg, params object[] args)
        {
            Output.Write("warning: ");
            Output.WriteLine(msg, args);
        }

        public void Error(string msg, params object[] args)
        {
            Output.Write("error: ");
            Output.WriteLine(msg, args);
        }

        public void Write(string format, params object[] args)
        {
            Output.Write(format, args);
        }

        public void WriteLine(string format, params object[] args)
        {
            Output.WriteLine(format, args);
        }


        public void WriteLine()
        {
            Output.WriteLine();
        }

        #endregion
    }

    public class ConsoleLogger : TextWriterLogger
    {
        public ConsoleLogger()
            : base(Console.Out)
        {
        }
    }

    /// <summary>
    /// Enables Logging in MSBuild format
    /// </summary>
    public class MSBuildLogger : ILogger
    {
        private readonly TextWriter Output;
        public List<ILogger> AdditionalLoggers = new List<ILogger>();
        public int Column;
        public string ErrorCode;
        public string Filename;
        public int Line;

        public MSBuildLogger(TextWriter output)
        {
            Output = output;
        }

        public MSBuildLogger(TextWriter output, string filename, int line, int column, string errorCode)
        {
            Output = output;
            Filename = filename;
            Line = line;
            Column = column;
            ErrorCode = errorCode;
        }

        #region ILogger Members

        public void Inform(string msg, params object[] args)
        {
            if (msg == null)
                return;
            //Output.Write("message: ");
            Output.WriteLine(msg, args);

            if (AdditionalLoggers != null)
                AdditionalLoggers.ForEach(l => l.Inform(msg, args));
        }

        public void Warn(string msg, params object[] args)
        {
            StartMessage("warning");
            Output.WriteLine(msg, args);
            if (AdditionalLoggers != null)
                AdditionalLoggers.ForEach(l => l.Warn(msg, args));
        }

        public void Error(string msg, params object[] args)
        {
            StartMessage("error");
            Output.WriteLine(msg, args);
            if (AdditionalLoggers != null)
                AdditionalLoggers.ForEach(l => l.Error(msg, args));
        }

        public void Write(string format, params object[] args)
        {
            Output.Write(format, args);
            if (AdditionalLoggers != null)
                AdditionalLoggers.ForEach(l => l.Write(format, args));
        }

        public void WriteLine(string format, params object[] args)
        {
            Output.WriteLine(format, args);
            if (AdditionalLoggers != null)
                AdditionalLoggers.ForEach(l => l.WriteLine(format, args));
        }


        public void WriteLine()
        {
            Output.WriteLine();
        }

        #endregion

        private void StartMessage(string errorKind)
        {
            string msg = String.Format("{0}({1},{2}): {3} {4}: ", Filename, Line, Column, errorKind, ErrorCode);
            Output.Write(msg);
            if (AdditionalLoggers != null)
                AdditionalLoggers.ForEach(l => l.Write(msg));
        }
    }
}